﻿using System;
using System.Collections.Generic;
using System.Text;

namespace MyGrid.Core.HexTypeA.Visual
{

    ///<summary>在所在锯齿线的上边沿或下边沿。</summary>
    public enum ReleationPositionInSerratedLine
    {
        Up, Down
    }

    ///<summary>在所在锯齿线的上边沿或下边沿。</summary>
    public enum SerratedLineDirection
    {
        ///<summary>中心方向向上箭头</summary>
        CenterUpArrow,

        ///<summary>中心方向向下箭头</summary>
        CenterDownArrow,
    }

    ///<summary>六边形的鼠标点击测试相关内容。</summary>
    public class HexTypeAHitTester
    {
        public static bool IsMouseInGrid(MGVector2I position, float unitSize, float zoomScale, MGVector2F focusCenter, MGVector2F mousePosition)
        {
            var finalUnitSize = unitSize * zoomScale;
            var visualPos = HexTypeALocator.GetVisualPosition(position, finalUnitSize, focusCenter);

            return IsInHexTypeAGrid(visualPos, finalUnitSize, mousePosition);
        }

        ///<summary>是否是在A型六边形网格内部。</summary>
        public static bool IsInHexTypeAGrid(MGVector2F hexCenter, float finalUnitSize, MGVector2F mousePosition)
        {
            // 方框边缘。
            {
                var width = MathExtensions.Sqrt3 * finalUnitSize;
                var left = hexCenter.X - MathExtensions.HalfSqrt3 * finalUnitSize;

                // 外边缘检测
                {
                    var top = hexCenter.Y - 1f * finalUnitSize;
                    var height = 2f * finalUnitSize;

                    if (IsInRect(new MGVector2F(left, top), new MGVector2F(width, height), mousePosition) == false)
                    {
                        return false;
                    }
                }

                // 内边缘检测
                {
                    var top = hexCenter.Y - 1f / 2f * finalUnitSize;
                    var height = 1f * finalUnitSize;

                    if (IsInRect(new MGVector2F(left, top), new MGVector2F(width, height), mousePosition) == true)
                    {
                        return true;
                    }
                }
            }

            // 在三角形区域空隙的部分。
            {
                var vx = Math.Abs(mousePosition.X - hexCenter.X);
                var vy = Math.Abs(mousePosition.Y - hexCenter.Y);
                var lOP = vx;
                var lAQ = lOP * MathExtensions.Tan30Degree;
                var lOA = finalUnitSize;

                var vy2 = lOA - vy;

                return vy2 >= lAQ;
            }

        }

        ///<summary>是否在矩形内部。</summary>
        private static bool IsInRect(MGVector2F leftTop, MGVector2F size, MGVector2F mousePosition)
        {
            if (mousePosition.X < leftTop.X) return false;
            if (mousePosition.Y < leftTop.Y) return false;
            if (mousePosition.X > leftTop.X + size.X) return false;
            if (mousePosition.Y > leftTop.Y + size.Y) return false;
            return true;
        }

        public static MGVector2I ConvertPosToGridId(MGVector2F mousePos, float finalUnitSize, MGVector2F focusCenter)
        {
            // 进行偏移矫正后的输入位置。
            var originInputPos = new MGVector2F(mousePos.X + focusCenter.X, mousePos.Y + focusCenter.Y);

            // 检测所在行。

            var yId = ConvertPosToGridYId(originInputPos, finalUnitSize);

            // 检测所在列。
            var xId = ConvertPosToGridXId(originInputPos, finalUnitSize, yId);

            return new MGVector2I(xId, yId);
        }

        public static int ConvertPosToGridYId(MGVector2F originInputPos, float finalUnitSize)
        {
            var serratedLineYId = (int)Math.Floor(originInputPos.Y / (1.5 * finalUnitSize));

            var releationPosInSerrateLine = GetReleationPositionInSerratedLine(serratedLineYId, finalUnitSize, originInputPos);

            if (releationPosInSerrateLine == ReleationPositionInSerratedLine.Up) return serratedLineYId;
            return serratedLineYId + 1;
        }

        public static int ConvertPosToGridXId(MGVector2F originInputPos, float finalUnitSize, int yId)
        {
            if (yId % 2 == 0)
            {
                var result = (int)Math.Floor((originInputPos.X + finalUnitSize * MathExtensions.HalfSqrt3) / (finalUnitSize * MathExtensions.Sqrt3));
                return result;
            }
            else
            {
                var result = (int)Math.Ceiling(originInputPos.X / (finalUnitSize * MathExtensions.Sqrt3));
                return result;
            }
        }

        ///<summary>获得输入点在指定锯齿线的哪个边沿方向</summary>
        public static ReleationPositionInSerratedLine GetReleationPositionInSerratedLine(
            int yId,
            float finalUnitSize,
            MGVector2F pos)
        {
            var arrowCenterInfo = GetArrowCenterYFromYId(yId, finalUnitSize);

            var direction = arrowCenterInfo.Item2;
            var arrowCenterY = arrowCenterInfo.Item1;

            return GetReleationPositionInSerratedLine(direction, arrowCenterY, finalUnitSize, pos);
        }

        ///<summary>获得箭头中心向上的点的位置。</summary>
        public static (float, SerratedLineDirection) GetArrowCenterYFromYId(int yId, float finalUnitSize)
        {
            if (yId % 2 == 0)
            {
                var ry = (1f * yId + 2f / 3f) * finalUnitSize * 3f / 2f;
                return (ry, SerratedLineDirection.CenterDownArrow);
            }
            else
            {
                var ry = (1f * yId + 1f / 3f) * finalUnitSize * 3f / 2f;
                return (ry, SerratedLineDirection.CenterUpArrow);
            }
        }

        ///<summary>获得输入点在指定锯齿线的哪个边沿方向</summary>
        public static ReleationPositionInSerratedLine GetReleationPositionInSerratedLine(
            SerratedLineDirection serratedLineDirection,
            float serrtedLineArrowEndY,
            float finalUnitSize,
            MGVector2F pos)
        {
            var ty = GetSerratedLineY(serrtedLineArrowEndY, serratedLineDirection, pos.X, finalUnitSize);

            if (pos.Y <= ty)
            {
                return ReleationPositionInSerratedLine.Up;
            }
            return ReleationPositionInSerratedLine.Down;
        }

        ///<summary>获得锯齿线的位置。</summary>
        public static float GetSerratedLineY(float arrowY, SerratedLineDirection direction, float x, float finalUnitSize)
        {
            var normalx = Math.Abs(x) % (MathExtensions.Sqrt3 * finalUnitSize);
            if (normalx >= (MathExtensions.HalfSqrt3 * finalUnitSize))
                normalx = MathExtensions.Sqrt3 * finalUnitSize - normalx;

            if (direction == SerratedLineDirection.CenterDownArrow)
            {
                var x1 = 0f;
                var y1 = arrowY;
                var x2 = MathExtensions.HalfSqrt3 * finalUnitSize;
                var y2 = arrowY - 1f / 2f * finalUnitSize;
                return GetLineY(x1, y1, x2, y2, normalx);
            }
            else
            {
                var x1 = 0f;
                var y1 = arrowY;
                var x2 = MathExtensions.HalfSqrt3 * finalUnitSize;
                var y2 = arrowY + 1f / 2f * finalUnitSize;
                return GetLineY(x1, y1, x2, y2, normalx);
            }
        }

        private static float GetLineY(float x1, float y1, float x2, float y2, float x)
        {
            var m = (y2 - y1) / (x2 - x1);
            return m * (x - x1) + y1;
        }
    }
}
